package com.mayikt.template;

import com.mayikt.constant.PayConstant;
import com.mayikt.entity.PaymentChannelEntity;
import com.mayikt.entity.PaymentTransactionEntity;
import com.mayikt.feign.IntegralServiceFeign;
import com.mayikt.manage.IntegralServiceManage;
import com.mayikt.mapper.PaymentTransactionMapper;
import com.mayikt.service.req.dto.IntegralReqDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

/**
 * @Name AbstractPayCallbackTemplate
 * @Author 枫火
 * @Date 2021/7/15 7:17
 * @Description 模板方法骨架类
 **/
@Slf4j
public abstract class AbstractPayCallbackTemplate {

    @Autowired
    private PayThreadInfoHolder payThreadInfoHolder;
    @Autowired
    private PaymentTransactionMapper paymentTransactionMapper;
    @Autowired
    private IntegralServiceManage integralServiceManage;

    public String asyncCallBack(PaymentChannelEntity pce) {
        // 1. 验证签名
        boolean isSign = verifySignature(pce);
        // 2. 记录日志 注意问题：一定要异步处理（为了快速响应给支付宝避免重试造成的幂等性问题）
        addPayLog();
        if (!isSign) {
            // 银联支付的时候 必须返回ok；支付宝必须返回success
            return resultFail();
        }
        // 更改订单状态 获取订单号码，支付金额
        String orderNo = getPayOrderNo();
        Long totalAmount = getTotalAmount();
        return asyncService(orderNo, totalAmount);
    }

    /**
     * 3.更改订单状态已经支付
     * 4.调用积分服务接口增加积分
     *
     * @return
     */
    private String asyncService(String outTradeNo, Long totalAmount) {
        // 支付订单号码
        PaymentTransactionEntity pte = paymentTransactionMapper.selectByPaymentId(outTradeNo);
        // 以下代码可以重构进入父类里面
        if (PayConstant.PAY_PAID_STATUS.equals(pte.getPaymentStatus())) {
            // 返回成功告诉给支付不要再继续重试
            return resultSuccess();
        }
        // 2.判断支付的金额 是否一致
        Long payAmount = pte.getPayAmount();
        if (!payAmount.equals(totalAmount)) {
            // 返回success，后台将该订单状态修改为异常订单状态，然后分析异常原因用定时任务处理
            return resultSuccess();
        }
        // 3. 在修改为已经支付
        int result = paymentTransactionMapper.updatePaymentStatus(PayConstant.PAY_PAID_STATUS + "", outTradeNo, "ali_pay");
        if (result < PayConstant.DB_FAIL) {
            // 返回失败告诉支付宝重试
            return resultFail();
        }
        // 调用积分服务接口增加积分 存在分布式事务的问题
        IntegralReqDto integralReqDto = new IntegralReqDto(pte.getUserId(), pte.getPaymentId(), 1000L);
        // 采用多线程一步形式调用积分接口增加积分 MQ增加积分更好（自带补偿功能）
        integralServiceManage.addIntegral(integralReqDto);
        return resultSuccess();
    }

    /**
     * 获取真实的支付订单号码
     *
     * @return
     */
    protected abstract String getPayOrderNo();

    /**
     * 获取真实的支付金额
     *
     * @return
     */
    protected abstract Long getTotalAmount();

    /**
     * 交给子类实现
     *
     * @return
     */
    protected abstract String resultFail();


    /**
     * 返回成功
     *
     * @return
     */
    protected abstract String resultSuccess();

    /**
     * 定义成抽象方法让子类实现
     * 不管验证签名成功还是失败都会将参数放入到ThreadLocal中
     *
     * @return
     */
    protected abstract boolean verifySignature(PaymentChannelEntity pce);

    /**
     * 将该方法单独放入在一个类中调用，@Async不经过代理类不会生效
     */
    public void addPayLog() {
        // 从ThreadLocal中获取
        Map<String, String> requestParams = currentRequestParams();
        log.info(">>>记录支付的日志requestParams:<<<" + requestParams);
    }

    protected Map<String, String> currentRequestParams() {
        return payThreadInfoHolder.getRequestParams();
    }

}
